package cn.net.isir.common;

//import com.sq.core.shiro.session.CustomSessionManager;
//import com.sq.core.shiro.token.SampleRealm;
//import com.sq.core.shiro.token.ShiroToken;
//import com.sq.entity.User;
//import com.sq.util.SpringContextUtil;

import cn.net.isir.core.ShiroAuthorizingRealm;
import cn.net.isir.core.ShiroToken;
import cn.net.isir.core.SpringApplicationContextUtils;
import cn.net.isir.entity.User;
import cn.net.isir.entity.UserInfo;
import cn.net.isir.service.UserInfoService;
import cn.net.isir.service.UserService;
import cn.net.isir.utils.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.session.Session;

import java.util.List;

/**
 * Shiro管理下的Token工具类
 */
public class TokenManager {
    // 用户登录管理
    private static final ShiroAuthorizingRealm realm = SpringApplicationContextUtils.getBean("sampleRealm", ShiroAuthorizingRealm.class);
    // 用户信息管理
    private static final UserService userService = SpringApplicationContextUtils.getBean("userService", UserService.class);
    // 用户附加信息管理
    private static final UserInfoService userInfoService = SpringApplicationContextUtils.getBean("userInfoService", UserInfoService.class);
    // 用户session管理
    //public static final CustomSessionManager customSessionManager = SpringContextUtil.getBean("customSessionManager",
    //CustomSessionManager.class);

    /**
     * 获取当前登录的用户User对象
     *
     * @return 当前登录的用户信息
     */
    public static User getToken() {
        String username = (String) SecurityUtils.getSubject().getPrincipal();
        User user = new User();
        user.setUsername(username);
        user = userService.selectOne(user);
        if (user == null) {
            return null;
        }
        return user;
    }

    /**
     * 加密用户的密码
     *
     * @param username 用户名（盐）
     * @param pwd      密码
     * @return 返回用户信息
     */
    public static String getMD5SaltPwd(String username, String pwd) {
        return new SimpleHash("MD5", pwd, username, 1024).toHex();
    }

    /**
     * 注册用户
     *
     * @param user 用户信息，必填项：用户名+密码+用户类型
     * @return 新增结果：100表示新增成功；
     * 101表示用户名或密码或类型为空；
     * 103表示用户名已经存在
     */
    public synchronized static ResultObject register(User user, UserInfo userInfo) {
        ResultObject ro = new ResultObject();
        //判断用户名密码是否都已填写
        if (StringUtils.isBlank(user.getUsername()) ||
                StringUtils.isBlank(user.getPassword()) ||
                StringUtils.isBlank(user.getUserType())) {
            ro.setResult(101);
            ro.setMessage("username or password is blank!");
            return ro;
        }
        //判断用户是否已存在
        User u = new User();
        u.setUsername(user.getUsername());
        u = userService.selectOne(u);
        if (u != null) {
            ro.setResult(103);
            ro.setMessage("user[" + user.getUsername() + "] is already exist!");
            return ro;
        }
        //将密码加密后进行存储
        user.setPassword(getMD5SaltPwd(user.getUsername(), user.getPassword()));
        userService.insert(user);
        user = userService.selectByPrimaryKey(user.getId());
        if (user != null) {
            // 添加用户附加信息
            if (userInfo != null) {
                userInfo.setUserId(user.getId());
                userInfoService.insert(userInfo);
                userInfo = userInfoService.selectByPrimaryKey(userInfo.getId());
                if (userInfo == null) {
                    ro.setResult(105);
                    ro.setMessage("userinfo add fail.");
                    return ro;
                }
            }
            ro.setResult(100);
            ro.setMessage("user[" + user.getUsername() + "] add successful!");
            ro.setObject(user);
            return ro;
        }
        ro.setResult(104);
        ro.setMessage("other errors...");
        return ro;
    }

    /**
     * 编辑用户信息
     *
     * @param user 用户信息
     * @return 编辑用户
     */
    public synchronized static ResultObject editUser(User user, UserInfo userInfo) {
        ResultObject ro = new ResultObject();

        if (StringUtils.isBlank(user.getId())) {
            ro.setResult(101);
            ro.setMessage("user id is not exist!");
            return ro;
        }
        User u = userService.selectByPrimaryKey(user.getId());
        if (u == null) {
            ro.setResult(102);
            ro.setMessage("user is not exist!");
            return ro;
        }
        if (StringUtils.isNotBlank(user.getPassword())) {
            user.setPassword(TokenManager.getMD5SaltPwd(u.getUsername(), user.getPassword()));
            userService.update(user);
        }
        // 更新用户信息
        if (userInfo != null) {
            UserInfo ui = new UserInfo();
            ui.setUserId(user.getId());
            ui = userInfoService.selectOne(ui);
            if (ui != null) {
                userInfo.setId(ui.getId());
                userInfoService.update(userInfo);
            }
        }
        ro.setResult(100);
        ro.setMessage("edit successful!");
        return ro;
    }

    /**
     * 删除用户
     *
     * @param id 用户id
     * @return 删除结果，删除成功为true，失败为false
     */
    public synchronized static ResultObject deleteUser(String id) {
        ResultObject ro = new ResultObject();
        if (StringUtils.isBlank(id)) {
            ro.setResult(101);
            ro.setMessage("id is blank!");
            return ro;
        }
        //删除主用户信息
        User u = userService.selectByPrimaryKey(id);
        if (u == null) {
            ro.setResult(102);
            ro.setMessage("user is not exist!");
            return ro;
        }
        userService.delete(id);
        u = userService.selectByPrimaryKey(id);
        if (u == null) {
            //删除用户附加信息
            UserInfo ui = new UserInfo();
            ui.setUserId(id);
            ui = userInfoService.selectOne(ui);
            if (ui != null) {
                userInfoService.delete(ui.getId());
            }
            ro.setResult(100);
            ro.setMessage("success");
            return ro;
        }
        ro.setResult(104);
        ro.setMessage("other errors...");
        return ro;
    }

    /**
     * 获取当前登录的用户User对象Id
     *
     * @return 当前登录的用户信息Id
     */
    public static String getTokenId() {
        User user = getToken();
        if (user != null) {
            return user.getId();
        }
        return null;
    }

    /**
     * 检查当前用户名密码是否匹配
     *
     * @param username 用户名
     * @param pwd      密码
     * @return 结果:true匹配，false不匹配
     */
    public static boolean checkPwd(String username, String pwd) {
        User user = new User();
        user.setUsername(username);
        user = userService.selectOne(user);
        if (user == null) {
            return false;
        }
        return user.getPassword().equals(new SimpleHash("MD5", pwd, username, 1024).toHex());
    }

    /**
     * 获取当前用户的Session
     *
     * @return 用户session
     */
    public static Session getSession() {
        return SecurityUtils.getSubject().getSession();
    }

    /**
     * 把值放入到当前登录用户的Session里
     *
     * @param key
     * @param value
     */
    public static void setVal2Session(Object key, Object value) {
        getSession().setAttribute(key, value);
    }

    /**
     * 从当前登录用户的Session里取值
     *
     * @param key
     * @return
     */
    public static Object getVal2Session(Object key) {
        return getSession().getAttribute(key);
    }

    /**
     * 获取验证码，获取一次后删除
     *
     * @return
     */
    public static String getYZM() {
        String code = (String) getSession().getAttribute("CODE");
        getSession().removeAttribute("CODE");
        return code;
    }

    /**
     * 登录
     *
     * @param user       用户信息
     * @param rememberMe 记住我
     * @return 登录的用户信息
     */
    public static User login(User user, Boolean rememberMe) {
        ShiroToken token = new ShiroToken(user.getUsername(), user.getPassword());
        token.setRememberMe(rememberMe);
        SecurityUtils.getSubject().login(token);
        return getToken();
    }

    /**
     * 判断是否登录
     *
     * @return 已登录返回是
     */
    public static boolean isLogin() {
        return SecurityUtils.getSubject().getPrincipal() != null;
    }

    /**
     * 退出登录
     */
    public static void logout() {
        SecurityUtils.getSubject().logout();
    }

    /**
     * 清空当前用户权限信息。 目的：为了在判断权限的时候，再次会再次 <code>doGetAuthorizationInfo(...)  </code>方法。
     * ps： 当然你可以手动调用 <code> doGetAuthorizationInfo(...)  </code>方法。
     * 这里只是说明下这个逻辑，当你清空了权限，<code> doGetAuthorizationInfo(...)  </code>就会被再次调用。
     */
    public static void clearNowUserAuth() {
        /**
         * 这里需要获取到shrio.xml 配置文件中，对Realm的实例化对象。才能调用到 Realm 父类的方法。
         */
        /**
         * 获取当前系统的Realm的实例化对象，方法一（通过 @link
         * org.apache.shiro.web.mgt.DefaultWebSecurityManager
         * 或者它的实现子类的{Collection<Realm> getRealms()}方法获取）。 获取到的时候是一个集合。Collection<Realm>
         * RealmSecurityManager securityManager = (RealmSecurityManager)
         * SecurityUtils.getSecurityManager(); SampleRealm realm =
         * (SampleRealm)securityManager.getRealms().iterator().next();
         */
        /**
         * 方法二、通过ApplicationContext 从Spring容器里获取实列化对象。
         */
        //realm.clearCachedAuthorizationInfo();
        /**
         * 当然还有很多直接或者间接的方法，此处不纠结。
         */
        realm.clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }

    /**
     * 根据UserIds 清空权限信息。
     */
    public static void clearUserAuthByUserId(Long... userIds) {

        if (null == userIds || userIds.length == 0)
            return;
//        List<SimplePrincipalCollection> result = customSessionManager.getSimplePrincipalCollectionByUserId(userIds);
//
//        for (SimplePrincipalCollection simplePrincipalCollection : result) {
//            realm.clearCachedAuthorizationInfo(simplePrincipalCollection);
//        }
    }

    /**
     * 方法重载
     *
     * @param userIds
     */
    public static void clearUserAuthByUserId(List<Long> userIds) {
        if (null == userIds || userIds.size() == 0) {
            return;
        }
        clearUserAuthByUserId(userIds.toArray(new Long[0]));
    }
}
